package ferp.core.ai.filter;

import ferp.core.ai.tree2.Evaluator;
import ferp.core.card.Card;
import ferp.core.game.Game;
import ferp.core.game.Trick;
import ferp.core.player.Hand;

/**
 * User: olegs
 * Date: 9/20/13 9:48 PM
 */
public class FilterWhisterAfterDeclarerMoveOpen
{
  /**
   * The basic idea of this filter is to beat declarer card with lowest possible cards.
   * In case there are no such cards in player's hand, use lowest candidates cards as candidates in order to reduce tree size.
   */
  public static int apply(Evaluator evaluator, int candidates, int[] hands, int player, int trick, Card.Suit trump, int round, int hand, int declarer)
  {
    int best = BEST_PAIR;
    int lc = getLowestCandidates(candidates);
    int filtered = 0;

    switch (hand)
    {
      case 1:
        int next = Game.next(player);
        int hand2 = hand + 1;
        int candidates2 = evaluator.doGetMoveCandidates(hands, next, trick, trump, round, hand2, declarer, true);

        for (int h1 = evaluator.start(candidates); h1 != 0; h1 = evaluator.next(candidates, h1))
        {
          Card c1 = Card.card(h1);
          trick = Trick.add(trick, player, c1.compressed);

          for (int h2 = evaluator.start(candidates2); h2 != 0; h2 = evaluator.next(candidates2, h2))
          {
            Card c2 = Card.card(h2);
            int sum = c1.rank.ordinal() + c2.rank.ordinal();
            trick = Trick.add(trick, next, c2.compressed);
            int winner = Trick.winner(trick, trump);

            if (winner != declarer && sum <= best)
            {
              filtered = sum < best ? c1.hash : Hand.add(filtered, c1);
              best = sum;
            }

            trick = Trick.pop(trick);
          }

          trick = Trick.pop(trick);
        }

        break;

      case 2:
        int winner = Trick.winner(trick, trump);

        if (winner == declarer)
        {
          Card c1 = Trick.card(trick, 1);

          for (int h = evaluator.start(candidates); h != 0; h = evaluator.next(candidates, h))
          {
            Card c2 = Card.card(h);
            int sum = c1.rank.ordinal() + c2.rank.ordinal();
            trick = Trick.add(trick, player, c2.compressed);
            winner = Trick.winner(trick, trump);

            if (winner != declarer && sum <= best)
            {
              filtered = sum < best ? c2.hash : Hand.add(filtered, c2);
              best = sum;
            }

            trick = Trick.pop(trick);
          }
        }
        else
          filtered = lc;

        break;
    }

    return filtered == 0 ? lc : filtered;
  }

  static int getLowestCandidates(int candidates)
  {
    int filtered = 0;

    for (Card.Suit s : Card.Suit.rising)
    {
      Card.Rank lowest = Card.Set.lowest(Card.Set.get(candidates, s));

      if (lowest != null)
        filtered = Hand.add(filtered, s, lowest);
    }

    return filtered;
  }

  private static final int BEST_PAIR = 2 * Card.Rank.ACE.ordinal();
}
